package com.wnn.demo.model.system.service;


import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.tobato.fastdfs.domain.StorePath;
import com.github.tobato.fastdfs.domain.ThumbImageConfig;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.wnn.demo.advice.MyException;
import com.wnn.demo.domain.*;
import com.wnn.demo.model.hospital.mapper.EmployeeMapper;
import com.wnn.demo.model.system.controller.UserController;
import com.wnn.demo.model.system.mapper.PermissionMapper;
import com.wnn.demo.model.system.mapper.UserMapper;
import com.wnn.demo.model.task.service.AccessoryService;
import com.wnn.demo.pojo.ResultCode;
import com.wnn.demo.shiro.MyRealm;
import com.wnn.demo.shiro.listener.ShiroSessionListener;
import com.wnn.demo.utils.IdWorker;
import com.wnn.demo.utils.Md5Utils;
import com.wnn.demo.utils.MyStringUtil;
import com.wnn.demo.vo.MenuTreeVo;
import com.wnn.demo.vo.UserVo;
import javafx.scene.Parent;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import tk.mybatis.mapper.entity.Example;


import javax.imageio.ImageIO;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author WN
 */
@Service
public class UserService {

    @Autowired(required=false)
    private UserMapper userMapper;

    @Autowired(required=false)
    private PermissionMapper permissionMapper;

    @Autowired(required=false)
    private EmployeeMapper employeeMapper;

    @Autowired
    private AccessoryService accessoryService;

    @Autowired
    private Accessory accessory;


    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ThumbImageConfig thumbImageConfig;

    @Autowired
    private FastFileStorageClient storageClient;

    @Autowired
    private ShiroSessionListener shiroSessionListener;

    @Autowired
    private UserService userService;


    public User findUserByName(String userName) { return userMapper.findUserByName(userName); }
    /**
     * 用户注册
     * @param user 用户对象
     * @return
     */

    public int registerUser(User user) {

        String id = idWorker.nextId() + "";
        user.setUserId(id);
        user.setAccount(user.getAccount());
        user.setTypes(user.getTypes());
        user.setSex(user.getSex());
        user.setIdcard(user.getIdcard());
        user.setUserName(user.getUserName());
        user.setPhonenumber(user.getPhonenumber());
        user.setUserPassword(Md5Utils.myEncryptPassword(user.getUserPassword(), user.getUserName(), 10));
        Date date = new Date();
        Timestamp timeStamp = new Timestamp(date.getTime());
        user.setCreateTime(timeStamp);
        user.setStatus(1);
        int res = userMapper.insertInto(user);
        String hiddenFilePath = user.getHiddenFilePath();
        String[] split = hiddenFilePath.split(",");
        for (String s : split) {
            String idd = idWorker.nextId() + "";
            accessory.setId(idd);
            accessory.setAccessoryId(id);
            accessory.setFilePath(s);
            accessoryService.saveFile(accessory);
        }
        if (user.getTypes() == 1 || user.getTypes() == 2) {
            for (int i = 0; i < 3; i++) {
                String userRoleid = idWorker.nextId() + "";
                user.setUserRoleid(userRoleid);
                if (i == 0) {
                    user.setRoleId("1177777889171644416");
                } else if (i == 1) {
                    user.setRoleId("1177782618542968832");
                } else if (i == 2) {
                    user.setRoleId("1197321690909016064");
                }
                int resp = userMapper.addPermission(user);
            }
        } else if (user.getTypes() == 0) {
            String userRoleid = idWorker.nextId() + "";
            user.setUserRoleid(userRoleid);
            user.setRoleId("1444528938614448128");
            int resp = userMapper.addPermission(user);
        }

        return res;

    }

    public int registerCheck(User user) {
        return userMapper.registerCheck(user);
    }

    /**
     * 新增用户
     * @param user 用户对象
     * @return
     */
    public int insertUser(User user) {
        if (user.getUserName()==null){
            throw new MyException(ResultCode.NULL,"用户名为空");
        }

        User name = userMapper.findUserByName(user.getUserName());

        if (name!=null&&user.getUserName().equals(name.getUserName())){
            throw new MyException(ResultCode.NULL,"用户名已存在");
        }
        String id = idWorker.nextId() + "";
        // 获取一个Date对象
        Date date = new Date();
        Timestamp timeStamp = new Timestamp(date.getTime());

        user.setCreateTime(timeStamp);
        user.setUserPassword(Md5Utils.myEncryptPassword(user.getUserPassword(),user.getUserName(),10));
        user.setUserId(id);
        user.setStatus(1);
        return userMapper.insert(user);


    }

    /**
     * 保存用户信息
     * @param userView
     * @return
     */
    public int saveUser(User userView) {
        //校验
        if (MyStringUtil.isNullOrEmpty(userView.getUserName())){
            throw new MyException(ResultCode.NULL,"用户名不能为空！");
        }
//        if (MyStringUtil.isNullOrEmpty(userView.getUserPassword())){
//            throw new MyException(ResultCode.NULL,"密码不能为空！");
//        }
        if (!MyStringUtil.isNullOrEmpty(userView.getUserPassword())){
            userView.setUserPassword(Md5Utils.myEncryptPassword(userView.getUserPassword(),userView.getUserName(),10));
        }else {
            userView.setUserPassword(null);
        }
        //解除账户和员工外键关系 由于外键原因只能设为 null
        if (MyStringUtil.isNullOrEmpty(userView.getEmployeeId())){
            User userDB = userMapper.selectByPrimaryKey(userView);
            userDB.setEmployeeId(null);
            userMapper.updateByPrimaryKey(userDB);
        }
        Example example = new Example(User.class);
        example.createCriteria().andEqualTo("userId",userView.getUserId());
        int i = userMapper.updateByExampleSelective(userView,example);
//        if (user.getStatus()==1&&i>0){
//            new RetryLimitHashedCredentialsMatcher().unlockAccount(user.getUserName());
//        }
        return i;
    }

    /**
     * 根据ID删除一个用户
     * @param id
     */
    @RequiresPermissions(value = "USER-DELETE")
    public void deleteById(String id) {

            User user1 = userMapper.selectByPrimaryKey(id);
            if (user1==null){
               throw new MyException(ResultCode.NULL);
            }

            int i = userMapper.deleteByPrimaryKey(user1);
            if (i!=1){
                throw new MyException(ResultCode.ERROR);
            }
    }

    /**
     * 链表查询了用户的角色和权限
     * @param id
     * @return user
     */
    public List< Map<String,Object> > findUserById(String id) {
        return userMapper.findUserById(id);
    }

    /**
     * 分配用户角色
     * @param userId
     * @param roleIds
     * @return
     */
    public int assignUserRoles(String userId,String roleIds) {

        User user = userMapper.selectByPrimaryKey(userId);
        if (user==null){
        throw new MyException(ResultCode.NULL);
        }
        if (roleIds==null){
            throw new MyException(ResultCode.NULL);
        }
        ArrayList<  String > dataIds = new ArrayList<>();
        ArrayList<String> ids = new ArrayList<>(Arrays.asList( roleIds.split(",")));

//      根据用户id找到中间表user_role包含用户id的所有信息
        List< UserAndRole > userAndRoless = userMapper.selectUserAndRoleListByUserId(userId);
        for (UserAndRole ur:userAndRoless
             ) {
            dataIds.add(ur.getRoleId());
        }
        ArrayList< String > deleteIds = new ArrayList<>();
        ArrayList<  String > insertIds = new ArrayList<>();

//      删除ids
        for (String id: dataIds
        ) {
            if (!ids.contains(id)){
                deleteIds.add(id);
            }
        }
//      增加
        for (String id: ids
        ) {
            if (!dataIds.contains(id)&&!"".equals(id)){
                insertIds.add(id);
            }
        }

        List< UserAndRole > insertUserAndRoles = new ArrayList<>();
        for (String roleId:insertIds
             ) {
            UserAndRole userAndRole = new UserAndRole(idWorker.nextId() + "",userId,roleId);
            insertUserAndRoles.add(userAndRole);
        }

        if (insertUserAndRoles.size()>0){
            int i = userMapper.batchInsertUserAndRoleList(insertUserAndRoles);
        }

        if (deleteIds.size()>0){
            int j = userMapper.batchDeleteUserAndRoleList(userId,deleteIds);
        }

//       角色、权限更新后 需要清除所有用户的授权缓存
        DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
        MyRealm shiroRealm = (MyRealm) securityManager.getRealms().iterator().next();
        shiroRealm.clearAllCachedAuthorizationInfo();
        return 1;

    }

    /**
     * 查询全部用户的信息，链表查询了角色信息
     * @return user和role
     */
    public PageInfo< UserVo > findAll(Integer page, Integer limit) {
        PageHelper.startPage(page,limit);
        List<UserVo> users = userMapper.findUserList();
        return new PageInfo<>(users);
    }

    public User findUserHaveRoles(String userName) {
        User  user = userMapper.findUserHaveRolesByUserName(userName);
        System.out.println(user);
        return user;
    }

    /**
     * 批量删除用户
     * @param ids
     * @return int
     */
    public int batchDeleteUserByIds(String ids) {

        List< User > users = userMapper.selectUserListByIds(ids);

        if (users==null){
            throw new MyException(ResultCode.NULLPARM);
        }

        return  userMapper.batchDeleteUserByList(users);
    }

    public int setNewPassword(String id ,String fromWebPassword, String newPassword) {
        User user = userMapper.selectByPrimaryKey(id);
        String oldPassword = Md5Utils.myEncryptPassword(fromWebPassword, user.getUserName(), 10);
        if (!user.getUserPassword().equals(oldPassword)){
            throw  new MyException(ResultCode.NULL,"旧密码错误！");
        }
        user.setUserPassword(Md5Utils.myEncryptPassword(newPassword,user.getUserName(),10));

        return userMapper.updateByPrimaryKey(user);
    }


    /**
     * 设置允许上传的图片的类型
     */
    private static final List<String> SUFFIXES = Arrays.asList("image/png", "image/jpeg","image/gif");

    public String uploadImage(String userId,MultipartFile file) {

        try {
            User user = userMapper.selectByPrimaryKey(userId);
            //1.验证文件
            //验证文件的类型
            String contentType = file.getContentType();
            if (!SUFFIXES.contains(contentType)) {

                throw new MyException(ResultCode.IMAGEFORMATWRONG);
            }
            //验证文件的内容

            BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
            if (bufferedImage == null) {
                throw new MyException(ResultCode.IMAGECONTENTERROR );
            }

            // 2、将图片上传到FastDFS
            // 2.1、获取文件后缀名
            String extension = StringUtils.substringAfterLast(file.getOriginalFilename(), ".");
            // 2.2、上传
            StorePath storePath = this.storageClient.uploadImageAndCrtThumbImage(
                    file.getInputStream(), file.getSize(), extension, null);
//            //完整url
//            String fullImage =  "images.hospital.com:8001/"+storePath.getFullPath();

            // 获取缩略图路径
            String path = thumbImageConfig.getThumbImagePath(storePath.getFullPath());

            //缩略图url
            String thumbImage = "http://images.hospital.com:8001/"+path;

            Employee employee = employeeMapper.selectByPrimaryKey(user.getEmployeeId());
            employee.setImages(thumbImage);
            int i = employeeMapper.updateByPrimaryKey(employee);
            if (i>0){
                return thumbImage;
            }
            return null;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 登录首页根据用户名加载 左侧菜单列表
     * 如果用户的角色是idministrator查取所有权限菜单
     * @return
     */
    public List< MenuTreeVo > selectIndexMenu(){
        // 在登录的时候成功时候给session封装了 用户信息、拥有的角色权限
        Subject subject = SecurityUtils.getSubject();
        String username = (String) subject.getPrincipal();
        User user = userMapper.findUserHaveRolesByUserName(username);
        List< Role > roles = user.getRoles();
        if (roles==null||roles.isEmpty()){
            return null;
        }
        boolean isAdministrator =false;
        for (Role r:roles
        ) {
            if ("administrator".equals(r.getName())){
                isAdministrator =true;
                break;
            }
         }
        //权限如果是超级管理员查找全部菜单 包含不可见的菜单，如果是其他角色按照链表查询拥有的可见的菜单
        List< MenuTreeVo > menuTreeVoList = null;
        if (isAdministrator){
            menuTreeVoList = permissionMapper.selectPermMenuTreeVoListByUserNameAndType(null,1,null);
        }else {
              menuTreeVoList = permissionMapper.selectPermMenuTreeVoListByUserNameAndType(username,1,1);
        }
        //去重
        List<MenuTreeVo> distinctMenuTreeVoList = menuTreeVoList.stream().
                collect(Collectors.collectingAndThen(Collectors.toCollection(()
                        -> new TreeSet<>(Comparator.comparing(o -> o.getTitle()))), ArrayList::new));
        //排序 看两个如何 合一
        List< MenuTreeVo > sortMenuTreeVoList =
                distinctMenuTreeVoList.parallelStream().sorted(Comparator.comparing(Permission::getSortNumber)).collect(Collectors.toList());

        //用流集合找到第一级菜单
        List< MenuTreeVo > permParentList = sortMenuTreeVoList.stream()
                .filter(perm -> ("0".equals(perm.getParentId()) || MyStringUtil.isNullOrEmpty(perm.getParentId()) )  )
                .collect(Collectors.toList());
        //给第一级菜单封装子级菜单
        for (MenuTreeVo parentPerm:permParentList
             ) {
            parentPerm.setChildren(this.selectIndexChildMenu(parentPerm.getPermissionId(),sortMenuTreeVoList ));
        }
        return permParentList;
    }

    /**
     * 递归查找菜单
     * @param parentPermId  使用当前子类的ID
     * @param distinctMenuTreeVoList
     * @return
     */
    public List< MenuTreeVo > selectIndexChildMenu(String parentPermId, List< MenuTreeVo > distinctMenuTreeVoList ) {
        ArrayList< MenuTreeVo > childTreeVoList = new ArrayList<>();
        Iterator< MenuTreeVo > permIterator = distinctMenuTreeVoList.iterator();
        while (permIterator.hasNext()){
            MenuTreeVo childPerm = permIterator.next();
            String childPermParentId = childPerm.getParentId();
            if (parentPermId.equals(childPermParentId)){
                childPerm.setChildren(this.selectIndexChildMenu(childPerm.getPermissionId(),distinctMenuTreeVoList));
                childTreeVoList.add(childPerm);
            }
        }
        return childTreeVoList;
    }

    /**
     * 用户登录
     * @param username
     * @param password
     * @param remember
     * @param session
     */
    public User userLogin(String username ,String password,String captcha,Boolean remember , HttpSession session ) {

//         TODO 验证码校验      前端 验证码刷新待实现
//        String sessionCaptcha = (String) SecurityUtils.getSubject().getSession().getAttribute(UserController.KEY_CAPTCHA);
//        if (null == captcha || !captcha.equalsIgnoreCase(sessionCaptcha)) {
//            throw  new MyException(ResultCode.NULL,"验证码错误！");
//        }
        if (username == null || password == null) {
            throw  new MyException(ResultCode.NULL,"账号/密码不能为空");
        }

//      构建subject.login(upToken)登录
        Subject subject = SecurityUtils.getSubject();
        User user = userService.findUserByName(username);
//      把账号密码封装进shiro的UsernamePasswor对象中
        UsernamePasswordToken upToken = new UsernamePasswordToken(username,password,true);

//      再调用login方法进入realm的认证方法中处理
//        ThreadContext.remove(ThreadContext.SUBJECT_KEY);
        subject.login(upToken);

        // TODO session设置没什么意义，用户如果关闭浏览器，他下次在请求就没有这些session信息了
//        User user = this.findUserHaveRoles(username);
//        user.setUserPassword("null");
//        session.setAttribute("userInfo", username);
//        session.setAttribute("user",user);

        System.out.println(username+"用户登录");
        System.out.println("now online number is "+ shiroSessionListener.getSessionCount());
        return user;
    }


}
